﻿using System;
using System.Collections.Generic;
using System.Drawing;

namespace ClockwiseClient
{
    public class ClassGraphPrice : ClassGraph
    {
        int lineHeight, lineTop, lineCount;
        int stockCount = 0, startLine = 0, cursorLine = 0;
        List<Rectangle> lstTitleRect = new List<Rectangle>();
        int selectColumn = 0;
        bool sortByDesc = false;
        List<ClassStockItem> lstItem = new List<ClassStockItem>(); 

        public override void Paint(Graphics g, Rectangle rect)
        {
            this.rect = rect;
            if (format.LineAlignment != StringAlignment.Center) format.LineAlignment = StringAlignment.Center;
            if (format.Alignment != StringAlignment.Center) format.Alignment = StringAlignment.Center;
            String tips = "显示区域太小了";
            stringSize = g.MeasureString(tips, font);
            if (rect.Width < 320 || rect.Height < 60)
            {
                if (stringSize.Width > rect.Width)
                {
                    tips = "太小了";
                    stringSize = g.MeasureString(tips, font);
                }
                if (stringSize.Width > rect.Width || stringSize.Height > rect.Height) return;
                PointF pointF = new PointF(rect.Left + rect.Width / 2, rect.Top + rect.Height / 2 + stringSize.Height / 10);
                g.DrawString(tips, font, Brushes.Cyan, pointF, format);
                return;
            }
            ShowTitle(g, rect);
            ShowBaojia(g, rect);
            DrawCursor(g, rect, true);
        }

        public override EnumGraph GetGraphType() { return EnumGraph.GRAPH_PRICE; }

        void ShowTitle(Graphics g, Rectangle rect)
        {
            ClassStockData classStockData = (ClassStockData)ClassStock.GetInstance();
            int count = classStockData.classStockLabel.GetLabelCount();
            int left = rect.Left + 2;
            lineCount = (int) ((float) rect.Height / (stringSize.Height + 2));
            lineHeight = rect.Height / lineCount;
            do
            {
                if ((lineHeight + 1) * lineCount > rect.Height) break;
                lineHeight++;
            } while (true);
            lineTop = (rect.Height - lineHeight * lineCount) / 2 + rect.Top;
            PointF point;
            bool needTitleCell = lstTitleRect.Count == 0;
            for (int i = 0; i < count; i++)
            {
                int width = (int) (stringSize.Height * classStockData.classStockLabel.GetLabelWidth(i) / 2);
                if (left + width > rect.Right) break;
                string label = classStockData.classStockLabel.GetLabelName(i);
                Rectangle cell = new Rectangle(left, lineTop, width, lineHeight);
                if(needTitleCell) lstTitleRect.Add(cell);
                switch (i)
                {
                    case 0: 
                    case 1: 
                        format.Alignment = StringAlignment.Center; 
                        point = new Point(cell.Left + cell.Width / 2, cell.Top + cell.Height / 2 + lineHeight / 10);
                        break;
                    case 2: 
                        format.Alignment = StringAlignment.Near; 
                        point = new Point(cell.Left, cell.Top + cell.Height / 2 + lineHeight / 10);
                        break;
                    default: 
                        format.Alignment = StringAlignment.Far; 
                        point = new Point(cell.Right, cell.Top + cell.Height / 2 + lineHeight / 10);
                        break;
                }
                bool hot = i>0&&i==selectColumn;
                if (hot)
                {
                    string tempLabel;
                    if (sortByDesc)
                        tempLabel = "↓";
                    else
                        tempLabel = "↑";
                    tempLabel += label;
                    g.DrawString(tempLabel, fontBold, Brushes.Magenta, point, format);
                }
                else
                    g.DrawString(label, font, Brushes.White, point, format);
                left += width + 2;
            }
        }

        void ShowBaojia(Graphics g, Rectangle rect)
        {
            //
            ClassStockData classStockData = (ClassStockData)ClassStock.GetInstance();
            ClassFilter classFilter = classStockData.GetFilter();
            if (classFilter != null && stockCount != classFilter.GetCount())
            {
                stockCount = classFilter.GetCount();
                cursorLine = 0;
                startLine = 0;
            }

            int count = classStockData.classStockLabel.GetLabelCount();
            int idx;
            int top;
            string text;
            Brush brush;
            PointF point;
            lstItem.Clear();
            for (int j = 0; j < lineCount - 1; j++)
            {
                top = (int) (lineHeight * (j+1) + lineTop);
                if (top + lineHeight >= lineTop + rect.Height) break;
                idx = j + startLine;
                if (classFilter != null) idx = classFilter.GetIndex(idx);
                ClassStockItem si = classStockData.GetClassStockItem(idx);
                lstItem.Add(si);
                if (si == null) continue;
                int left = rect.Left + 2;
                for (int i = 0; i < count; i++)
                {
                    int width = (int)(stringSize.Height * classStockData.classStockLabel.GetLabelWidth(i) / 2);
                    if (left + width > rect.Right) break;
                    Rectangle cell = new Rectangle(left, top, width, lineHeight);
                    switch (i)
                    {
                        case 0: text = (j + startLine + 1).ToString(); 
                            brush = Brushes.Gray; 
                            format.Alignment = StringAlignment.Center; 
                            break;
                        case 1: text = si.code; 
                            brush = Brushes.Cyan; 
                            format.Alignment = StringAlignment.Center; 
                            break;
                        case 2: text = si.name;
                            brush = classStockData.ZixuanguInclude(si.symbol) ? Brushes.Magenta : Brushes.Yellow; 
                            format.Alignment = StringAlignment.Near; 
                            break;
                        case 3: text = si.trade;
                            brush = GetPriceColor(si.trade, si.settlement); 
                            format.Alignment = StringAlignment.Far; 
                            break;
                        case 4: text = si.changepercent.Remove(si.changepercent.Length-1) + "%";
                            brush = GetPriceColor(si.trade, si.settlement);
                            format.Alignment = StringAlignment.Far;
                            break;
                        case 5: text = si.pricechange;
                            brush = GetPriceColor(si.trade, si.settlement);
                            format.Alignment = StringAlignment.Far;
                            break;
                        case 6:
                            text = si.settlement;
                            brush = Brushes.White;
                            format.Alignment = StringAlignment.Far;
                            break;
                        case 7: text = si.buy;
                            brush = GetPriceColor(si.buy, si.settlement);
                            format.Alignment = StringAlignment.Far;
                            break;
                        case 8: text = si.sell;
                            brush = GetPriceColor(si.sell, si.settlement);
                            format.Alignment = StringAlignment.Far;
                            break;
                        case 9:
                            text = ClassStock.VolumeFormat(si.f_delta);
                            brush = Brushes.BlueViolet;
                            format.Alignment = StringAlignment.Far;
                            break;
                        case 10:
                            text = ClassStock.VolumeFormat(si.f_volume);
                            brush = Brushes.Yellow;
                            format.Alignment = StringAlignment.Far;
                            break;
                        case 11: text = si.open;
                            brush = GetPriceColor(si.open, si.settlement);
                            format.Alignment = StringAlignment.Far;
                            break;
                        case 12: text = si.high;
                            brush = GetPriceColor(si.high, si.settlement);
                            format.Alignment = StringAlignment.Far;
                            break;
                        case 13: text = si.low;
                            brush = GetPriceColor(si.low, si.settlement);
                            format.Alignment = StringAlignment.Far;
                            break;
                        case 14:
                            text = si.f_amplitude.ToString("f2") + "%";
                            brush = Brushes.Orange;
                            format.Alignment = StringAlignment.Far;
                            break;
                        case 15: 
                            float ztj = si.f_price * (si.name.IndexOf("ST") < 0 ? 1.1f : 1.05f);
                            text = ztj.ToString("f2");
                            brush = ClassStock.CalcColor(ztj, si.f_preclose);
                            format.Alignment = StringAlignment.Far;
                            break;
                        case 16:
                            float dtj = si.f_price * (si.name.IndexOf("ST") < 0 ? 0.9f : 0.95f);
                            text = dtj.ToString("f2");
                            brush = ClassStock.CalcColor(dtj, si.f_preclose);
                            format.Alignment = StringAlignment.Far;
                            break;
                        case 17:
                            text = ClassStock.AmountFormat(si.f_amount);
                            brush = Brushes.Cyan;
                            format.Alignment = StringAlignment.Far;
                            break;
                        default: text = ""; brush = Brushes.White; format.Alignment = StringAlignment.Center; break;
                    }
                    if (format.Alignment == StringAlignment.Near)
                        point = new PointF(cell.Left, cell.Top + 2 + cell.Height / 2 + stringSize.Height / 10);
                    else
                    if (format.Alignment == StringAlignment.Far)
                        point = new PointF(cell.Right, cell.Top + 2 + cell.Height / 2 + stringSize.Height / 10);
                    else
                        point = new PointF(cell.Left + cell.Width / 2, cell.Top + 2 + cell.Height / 2 + stringSize.Height / 10);
                    g.DrawString(text, font, brush, point, format);
                    left += width + 2;
                }
            }
            //
        }

        void DrawCursor(Graphics g, Rectangle rect, bool draw)
        {
            if (stockCount == 0) return;
            int row = (int)(lineHeight * (cursorLine + 2) + lineTop);
            g.DrawLine(new Pen(draw?Color.Gray:Color.Black, 1), rect.Left, row, rect.Right, row);
            if (draw)
            {
                me = lstItem[cursorLine];
            }
        }

        public int[] GetCursorTick(int count)
        {
            ClassStockData classStockData = (ClassStockData)ClassStock.GetInstance();
            ClassFilter classFilter = classStockData.GetFilter();
            if (classFilter != null && stockCount != classFilter.GetCount())
            {
                stockCount = classFilter.GetCount();
                cursorLine = 0;
                startLine = 0;
            }
            int idx;
            int[] ret = new int[count];
            for (int j = 0; j < count; j++)
            {
                idx = j + startLine;
                if (classFilter != null) idx = classFilter.GetIndex(idx);
                ClassStockItem si = classStockData.GetClassStockItem(idx);
                if (si != null)
                {
                    int market = si.symbol.StartsWith("sh") ? 0 : 1;
                    classStockData.LoadStockTick(market, si.code, j);
                }
                ret[j] = idx;
            }
            return ret;
        }

        Brush GetPriceColor(string now, string old)
        {
            float nowF = float.Parse(now);
            float oldF = float.Parse(old);
            return ClassStock.CalcColor(nowF, oldF);
        }

        public void MouseWheel(int delta, int step)
        {
            if (delta < 0)
            {
                startLine += step;
                if (startLine >= stockCount) startLine = 0;
            }
            else
            {
                if (startLine > 0)
                {
                    startLine -= step;
                }
                else
                {
                    startLine = stockCount - step;
                }
            }
            if (startLine < 0) startLine = 0;
            if (cursorLine + startLine > stockCount) cursorLine = stockCount - startLine - 1;
        }

        public override void MouseWheel(int delta)
        {
            if (delta < 0)
            {
                startLine += lineCount - 1;
                if (startLine >= stockCount) startLine = 0;
            }
            else
            {
                if (startLine > 0)
                {
                    startLine -= lineCount - 1;
                }
                else
                {
                    startLine = stockCount - (lineCount - 1);
                }
            }
            if (startLine < 0) startLine = 0;
            if (cursorLine + startLine > stockCount) cursorLine = stockCount - startLine - 1;
        }

        public override bool MouseClick(int x, int y, Graphics g)
        {
            int cursorTemp = (y - lineTop) / lineHeight - 1;
            if (cursorTemp >= 0 && cursorTemp < lineCount - 1 && cursorTemp != cursorLine && cursorTemp + startLine < stockCount)
            {
                DrawCursor(g, rect, false);
                cursorLine = cursorTemp;
                DrawCursor(g, rect, true);
                return true;
            }
            else
            {
                if (cursorTemp < 0)
                {
                    // 点中栏目，进行排序
                    int i = 0;
                    bool updateScreen = false;
                    foreach(Rectangle rect in lstTitleRect) 
                    {
                        if (x >= rect.Left && x < rect.Right && y >= rect.Top && y < rect.Bottom)
                        {
                            if (selectColumn != i)
                            {
                                selectColumn = i;
                            }
                            else
                            {
                                sortByDesc = !sortByDesc;
                            }
                            updateScreen = true;
                            break;
                        }
                        i++;
                    }
                    if (updateScreen) return true;
                }
            }
            return false;
        }


        public override bool MouseDouble(int x, int y, Graphics g)
        {
            int cursorTemp = (y - lineTop) / lineHeight - 1;
            if (cursorTemp >= 0 && cursorTemp < lineCount - 1 && cursorTemp == cursorLine && cursorTemp + startLine < stockCount)
            {
                KeyEnter();
                return true;
            }
            return false;
        }

        public override void KeyDown(Graphics g) 
        {
            DrawCursor(g, rect, false);
            if (cursorLine < lineCount - 2) cursorLine++; else cursorLine = 0;
            if (cursorLine + startLine >= stockCount) cursorLine = 0;
            DrawCursor(g, rect, true);
        }

        public override void KeyUp(Graphics g) 
        {
            DrawCursor(g, rect, false);
            if (cursorLine > 0) cursorLine--; else cursorLine = lineCount - 2;
            if (cursorLine + startLine > stockCount) cursorLine = stockCount - startLine - 1;
            DrawCursor(g, rect, true);
        }

        public override bool KeyEnter()
        {
            ClassStockData classStockData = (ClassStockData)ClassStock.GetInstance();
            classStockData.focusStockIdx = startLine + cursorLine;
            return true;
        }

        public override bool KeyHome()
        {
            if(startLine > 0)
            {
                startLine = 0;
                return true;
            }
            return false;
        }
        public override bool KeyEnd()
        {
            if(startLine < stockCount - (lineCount - 1))
            {
                startLine = stockCount - (lineCount - 1);
                return true;
            }
            return false;
        }
    }
}
